﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Net;

namespace Server {
	public class ServerNodeControl {
		protected IServiceModelServerCallback callback;
		protected Node node;

		public ServerNodeControl(Guid guid, ServiceModelServer serviceNode) {
			this.callback = (IServiceModelServerCallback) serviceNode.GetCallback();
			this.node = new Node(guid, serviceNode);
		}

		public Node Node {
			get {
				return node;
			}
		}

		public void TestPing(String testName, String host, int count, int interval, int timeout, bool async) {
			Logger.Debug(String.Format("#{0}/{6}: Testing ping to {1}, {2} times, with {3}ms interval and {4}s timeout. Ping will be async: {5}", node.Name, host, count, interval, timeout, async.ToString(), testName));
			try {
				callback.TestPing(testName, host, count, interval, timeout, async);
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (Testing ping)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (Testing ping)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (Testing ping)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
		}

		public Boolean WifiConnect(String ssid, WifiSecurityType securityType, WifiEncryptionType encryptionType, String securityKey) {
			Logger.Debug(String.Format("#{0}: Trying to connect to wifi with SSID: {1}, security type: {2}, encryption type: {3} and security key: {4}", node.Name, ssid, securityType, encryptionType, securityKey));
			try {
				return callback.WifiConnect(ssid, securityType, encryptionType, securityKey);
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (WLAN Connecting)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (WLAN Connecting)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (WLAN Connecting)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return false;
		}

		public Boolean WifiDisconnect() {
			Logger.Debug(String.Format("#{0}: Disconnecting from associated wifi", node.Name));
			try {
				return callback.WifiDisconnect();
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (WLAN Connecting)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (WLAN Connecting)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (WLAN Connecting)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return false;
		}

		public String[] GetLogs() {
			return GetLogs(0);
		}

		public String[] GetLogs(int index) {
			Logger.Debug(String.Format("#{0}: Getting logs from line {1}...", node.Name, index));
			try {
				return callback.GetLogs(index);
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (getting logs)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (gettings logs)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (gettings logs)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return new String[0];
		}

		public WifiConnectionState WifiGetConnectionState() {
			Logger.Debug(String.Format("#{0}: Getting wifi connection state...", node.Name));
			try {
				return callback.WifiGetConnectionState();
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (getting wifi connection state)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (getting wifi connection state)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (getting wifi connection state)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return new WifiConnectionState();
		}

		public Boolean TestConnection() {
			try {
				return callback.TestConnection();
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (testing connection)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (testing connection)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (testing connection)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return false;
		}

		public Dictionary<Guid, TestResult> GetTestResults() {
			try {
				return callback.GetTestResults();
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (getting test results)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (getting test results)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (getting test results)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return null;
		}

		public TestResult GetTestResult(Guid testGuid) {
			try {
				TestResult result = callback.GetTestResult(testGuid);

				Logger.Test(String.Format("Retrieved test result ID#{0} from Node#{1}", testGuid.ToString(), Node.Name.ToString()));

				FileLogger.SaveTest(result);

				return result;
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (getting test result)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (getting test result)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (getting test result)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return null;
		}

		public Boolean ContainsResult(Guid guid) {
			try {
				return callback.ContainsResult(guid);
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (checking test result)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (checking test result)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (checking test result)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return false;
		}

		public Guid[] GetTestResultList() {
			try {
				return callback.GetTestResultList();
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (getting test result list)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (getting test result list)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (getting test result list)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return new Guid[0];
		}

		public void StartCustomTestServer(String command, int timeout) {
			try {
				callback.StartCustomTestServer(command, timeout);
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (preparing custom test)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (preparing with custom test)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (preparing with custom test)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
		}

		public void StopCustomTestServer() {
			try {
				callback.StopCustomTestServer();
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (closing custom test)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (closing with custom test)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (closing with custom test)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
		}

		public Guid TestCustomTest(String testName, String command, int timeout) {
			try {
				return callback.TestCustomTest(testName, command, timeout);
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (testing with custom test)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (testing with custom test)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (testing with custom test)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
			return Guid.Empty;
		}

		public void Shutdown() {
			try {
				callback.Shutdown();
			} catch (TimeoutException) {
				Logger.Warning("Timeout exception (shutdown in progress)");
			} catch (CommunicationException) {
				Logger.Warning("Communication lost (shutdown in progress)");
				Server.Instance.RemoveNode(node.Name);
			} catch (NullReferenceException) {
				Logger.Critical("Service Null Exception (shutdown in progress)");
				Server.Instance.RemoveNode(node.Name);
			} catch (IndexOutOfRangeException) {
				// nothing?
				Server.Instance.RemoveNode(node.Name);
			} catch (ObjectDisposedException) {
				Logger.Critical("Object Disposed! Removing node...");
				Server.Instance.RemoveNode(node.Name);
			}
		}
	}
}
